﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace USpell
{
    public class SocketClient
    {
        public event EventHandler DataReceiveEvent;

        Socket socket = null;

        // 当一个异步操作完成时, 用于通知的事件对象
        static ManualResetEvent socketDone = new ManualResetEvent(false);

        // 异步操作超过时间定义. 如果在此时间内未接收到回应, 则放弃此操作.
        const int TIMEOUT_MILLISECONDS = 2000;

        // 最大接收缓冲
        const int MAX_BUFFER_SIZE = 40 * 1024;

        // Socket 连接到指定端口的服务器
        // hostName 服务器名称
        // portNumber 连接端口
        // 返回值: 连接结果返回的字符串
        public string Connect(string hostName, int portNumber)
        {
    

            string result = string.Empty;

            // 创建 DnsEndPoint. 服务器的端口传入此方法
            DnsEndPoint hostEntry = new DnsEndPoint(hostName, portNumber);

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // 创建一个 SocketAsyncEventArgs 对象用于连接请求
            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
            socketEventArg.RemoteEndPoint = hostEntry;

            // Inline event handler for the Completed event.
            // Note: This event handler was implemented inline in order to make this method self-contained.
            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
            {
                result = e.SocketError.ToString();
                // 标识请求已经完成, 不阻塞 UI 线程
                socketDone.Set();


            });

            socketDone.Reset();
            socket.ConnectAsync(socketEventArg);
            socketDone.WaitOne(TIMEOUT_MILLISECONDS);

            return result;
        }

        public string Send(string data)
        {
            string response = "Operation Timeout";

            if (socket != null)
            {
                // 创建 SocketAsyncEventArgs 对象、并设置对象属性
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
                socketEventArg.UserToken = null;

                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    response = e.SocketError.ToString();
                    socketDone.Set();
                }
                    );

                // 将需要发送的数据送入发送缓冲区
                byte[] payload = new byte[Encoding.UTF8.GetBytes(data).Length + 1];
                payload[0] = (byte)Encoding.UTF8.GetBytes(data).Length;
                Encoding.UTF8.GetBytes(data).CopyTo(payload, 1);
                socketEventArg.SetBuffer(payload, 0, payload.Length);

                socketDone.Reset();
                socket.SendAsync(socketEventArg);
                socketDone.WaitOne(TIMEOUT_MILLISECONDS);
            }
            else
            {
                response = "Socket is not initialized";
            }

            return response;
        }

        public string SendBye(string data)
        {
            string response = "Operation Timeout";

            if (socket != null)
            {
                // 创建 SocketAsyncEventArgs 对象、并设置对象属性
                SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
                socketEventArg.UserToken = null;

                socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                {
                    response = e.SocketError.ToString();
                    socketDone.Set();
                }
                    );

                // 将需要发送的数据送入发送缓冲区

                var arr = data.Split(new string[1] { " " }, StringSplitOptions.RemoveEmptyEntries);
                List<byte> re = new List<byte>();

                foreach (var hex in arr)
                {
                    int value = Convert.ToInt32(hex, 16);
                    re.Add((byte)value);
                }

                byte[] tmm=re.ToArray();

                byte[] payload = re.ToArray();
                //byte[] payload = new byte[tmm.Length+1];
                //payload[0] = (byte)tmm.Length;
                //tmm.CopyTo(payload, 1);

                socketEventArg.SetBuffer(payload, 0, payload.Length);

                socketDone.Reset();
                socket.SendAsync(socketEventArg);
                socketDone.WaitOne(TIMEOUT_MILLISECONDS);
            }
            else
            {
                response = "Socket is not initialized";
            }

            return response;
        }

        public void StartReceive()
        {
            ThreadPool.QueueUserWorkItem((o) =>
                {
                    while (true)
                    {
                        string response;
                        if (socket != null)
                        {
                            SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
                            socketEventArg.RemoteEndPoint = socket.RemoteEndPoint;
                            socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
            
                            socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
                            {
                                if (e.SocketError == SocketError.Success)
                                {
                                    // 从接收缓冲区得到数据
                                    if (DataReceiveEvent != null)
                                    {
                                        DataReceiveEvent(e.Buffer.Count(), null);
                                    }

                                    response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                                    response = response.Trim('\0');
                                 

                                    if (DataReceiveEvent != null)
                                    {
                                        DataReceiveEvent(response, null);
                                    }
                             
                                }
                                else
                                {
                                    response = e.SocketError.ToString();
                                }

                                socketDone.Set();
                            }
                                );

                            socketDone.Reset();

                            socket.ReceiveAsync(socketEventArg);

                            socketDone.WaitOne(TIMEOUT_MILLISECONDS);
                        }
                        else
                        {
                            response = "Socket is not initialized";
                        }
                    }
                });
        }

        /// <summary>
        /// Closes the Socket connection and releases all associated resources
        /// </summary>
        public void Close()
        {
            if (socket != null)
            {
                socket.Close();
            }
        }
    }
}